home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
ARGONET
/
PD
/
FILER
/
X-FILES.ZIP
/
057
/
!X-Files
/
c
/
compact
< prev
next >
Wrap
Text File
|
1996-04-22
|
6KB
|
197 lines
/* compact.c - Compaction routine triggered when the wasted space in an image
* gets above 10%
*/
#include "chunks.h"
#include "debug.h"
#include <stdlib.h>
#include "swis.h"
#define BATCHSIZE 100
#define _max(x, y) ((x) > (y) ? (x) : (y))
#define _min(x, y) ((x) < (y) ? (x) : (y))
typedef struct
{
unsigned cnkNum;
xFiles_chunk chunk;
} xFiles__chunkRef;
/* Yet another dodgy implementation of my standard shifting heap
* compactor. Each pass finds the chunk numbers of the next N items
* in the file, then relocates them down towards the header. Simple
* as that.
*/
_kernel_oserror *xFiles_Compact(xFiles_info *pInfo)
{
_kernel_oserror *err;
xFiles__chunkRef *workSpace = NULL;
unsigned tableSize, bitSize, nChunks, fileSize;
unsigned thisChunk;
unsigned highWaterMark = xFiles_roundUp(pInfo, sizeof(xFiles_header));
unsigned tablePos;
xFiles_chunk *pChunk;
int workUsed = 0;
int i;
_kernel_swi_regs regs;
if (pInfo->compacting)
return NULL;
pInfo->compacting = TRUE;
(void) _kernel_swi(Hourglass_On, ®s, ®s);
if (err = xFiles_getLength(pInfo, &fileSize), err) goto fail;
/*TRACE("Compacting file (size = %08x)\n", fileSize);*/
if (workSpace = malloc(BATCHSIZE * sizeof(xFiles__chunkRef)), !workSpace)
{
err = &xFiles_NoMemory;
goto fail;
}
do
{
/* Collect the next 100 candidates */
tableSize = pInfo->fileHeader.chunkTable.size;
tablePos = 0;
workUsed = 0;
thisChunk = 0;
if (err = xFiles_claimBuffer(tableSize), err)
goto fail;
while (tableSize > 0)
{
bitSize = _min(tableSize, xFiles_windowBufferSize);
nChunks = bitSize / sizeof(xFiles_chunk);
bitSize = nChunks * sizeof(xFiles_chunk);
if (err = xFiles_readChunk(pInfo, xFiles_windowBuffer, 0, tablePos, bitSize), err)
goto fail2;
for (pChunk = xFiles_windowBuffer; nChunks > 0; nChunks--, pChunk++, thisChunk++)
{
if (pChunk->usage != 0x45455246 && pChunk->offset >= highWaterMark)
{
xFiles__chunkRef ref, tmp;
ref.cnkNum = thisChunk;
ref.chunk = *pChunk;
for (i = 0; i < workUsed; i++)
{
if (ref.chunk.offset < workSpace[i].chunk.offset)
{
tmp = workSpace[i];
workSpace[i] = ref;
ref = tmp;
}
}
if (workUsed < BATCHSIZE)
workSpace[workUsed++] = ref;
}
}
tableSize -= bitSize;
tablePos += bitSize;
}
if (err = xFiles_releaseBuffer(), err)
goto fail;
/*TRACE("Identified %d chunks\n", workUsed);
for (i = 0; i < workUsed; i++)
{
TRACE("chunk %5d at %08x, size %08x, allocSize %08x\n",
workSpace[i].cnkNum, workSpace[i].chunk.offset,
workSpace[i].chunk.size, workSpace[i].chunk.allocSize);
}*/
/* Processed the whole table and got a few candidates for relocating, so let's
* shift them.
*/
for (i = 0; i < workUsed; i++)
{
if (workSpace[i].chunk.allocSize != xFiles_roundDown(pInfo, workSpace[i].chunk.allocSize))
TRACE("How strange: allocSize = %08x\n", workSpace[i].chunk.allocSize);
if (workSpace[i].chunk.allocSize < xFiles_roundUp(pInfo, workSpace[i].chunk.size))
TRACE("How odd: allocSize = %08x, size = %08x\n",
workSpace[i].chunk.allocSize, workSpace[i].chunk.size);
if (workSpace[i].chunk.offset != xFiles_roundDown(pInfo, workSpace[i].chunk.offset))
TRACE("How weird: offset = %08x\n", workSpace[i].chunk.offset);
ASSERT(workSpace[i].chunk.allocSize >= workSpace[i].chunk.size);
ASSERT(workSpace[i].chunk.offset >= sizeof(xFiles_header));
workSpace[i].chunk.allocSize = xFiles_roundUp(pInfo, workSpace[i].chunk.size);
/*TRACE("Moving %08x bytes from %08x to %08x\n",
workSpace[i].chunk.allocSize, workSpace[i].chunk.offset, highWaterMark);*/
if (workSpace[i].chunk.offset < highWaterMark && workSpace[i].chunk.allocSize != 0)
{
TRACE("*** can't move block from %08x to %08x\n",
workSpace[i].chunk.offset, highWaterMark);
goto skip;
}
regs.r[0] = 100 * (workSpace[i].chunk.offset >> 8) / (fileSize >> 8);
(void) _kernel_swi(Hourglass_Percentage, ®s, ®s);
if (err = xFiles_moveBlock(pInfo, highWaterMark, workSpace[i].chunk.offset, workSpace[i].chunk.allocSize), err)
goto fail;
workSpace[i].chunk.offset = highWaterMark;
if (err = xFiles_setChunkInfo(pInfo, workSpace[i].cnkNum, &workSpace[i].chunk), err)
goto fail;
skip:
highWaterMark += workSpace[i].chunk.allocSize;
if (xFiles_roundDown(pInfo, highWaterMark) != highWaterMark)
{
TRACE("Huh? HWM = %08x\n", highWaterMark);
}
}
} while (workUsed == BATCHSIZE);
free(workSpace);
/*TRACE("Compacted file (size = %08x)\n", highWaterMark);*/
if (err = xFiles_setLength(pInfo, highWaterMark), err)
goto fail;
pInfo->fileHeader.waste = 0;
if (err = xFiles_updateHeader(pInfo), err)
goto fail;
pInfo->flags |= xFiles_fNeedTruncate;
(void) _kernel_swi(Hourglass_Off, ®s, ®s);
pInfo->compacting = FALSE;
return err;
fail2:
(void) xFiles_releaseBuffer();
fail:
if (workSpace) free(workSpace);
pInfo->compacting = FALSE;
(void) _kernel_swi(Hourglass_Off, ®s, ®s);
return err;
}